cmake_minimum_required(VERSION 3.13)
project(PAG)

# Uncomment the next 4 lines to build libpag for Intel cpus on Apple Silicon devices.
#if (APPLE AND NOT IOS)
#    SET(CMAKE_SYSTEM_PROCESSOR x86_64)
#    SET(CMAKE_OSX_ARCHITECTURES x86_64)
#endif ()

# Uncomment the next line to enable debug mode for third-party libraries.
#set(VENDOR_DEBUG ON)
#set(CMAKE_VERBOSE_MAKEFILE ON)


include(./third_party/vendor_tools/vendor.cmake)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
cmake_policy(SET CMP0063 NEW)
set(CMAKE_CXX_VISIBILITY_PRESET hidden)

# Options for building libpag
option(PAG_USE_OPENGL "Allow use of OpenGL as GPU backend" ON)
option(PAG_USE_SWIFTSHADER "Allow build with SwiftShader library" OFF)
option(PAG_USE_QT "Allow build with QT frameworks" OFF)
option(PAG_USE_RTTR "Enable RTTR support" OFF)
option(PAG_USE_HARFBUZZ "Enable HarfBuzz support" OFF)
option(PAG_USE_C "Enable c API" OFF)

if (NOT MACOS AND NOT IOS AND NOT WEB)
    option(PAG_USE_FREETYPE "Allow use of embedded freetype library" ON)
endif ()

if (IOS OR WEB)
    option(PAG_USE_WEBP_DECODE "Enable embedded WEBP decoding support" ON)
elseif (ANDROID)
    option(PAG_USE_FFAVC "Allow use of embedded ffavc as fallback video decoder" ON)
else ()
    option(PAG_USE_PNG_DECODE "Enable embedded PNG decoding support" ON)
    option(PAG_USE_PNG_ENCODE "Enable embedded PNG encoding support" ON)
    option(PAG_USE_JPEG_DECODE "Enable embedded JPEG decoding support" ON)
    option(PAG_USE_JPEG_ENCODE "Enable embedded JPEG encoding support" ON)
    option(PAG_USE_WEBP_DECODE "Enable embedded WEBP decoding support" ON)
    option(PAG_USE_WEBP_ENCODE "Enable embedded WEBP encoding support" ON)
endif ()

if (NOT WEB)
    if (NOT IOS OR SDK_NAME STREQUAL iphonesimulator)
        option(PAG_USE_LIBAVC "Allow use of embedded libavc as fallback video decoder" ON)
    endif ()
    option(PAG_BUILD_SHARED "Allow build shared library" ON)
endif ()

if (MACOS OR IOS)
    option(PAG_BUILD_FRAMEWORK "Allow build framework" ON)
else ()
    set(PAG_BUILD_FRAMEWORK OFF)
endif ()

if ($ENV{CLION_IDE})
    set(CLION_IDE ON)
else ()
    set(CLION_IDE OFF)
endif ()
get_directory_property(HasParent PARENT_DIRECTORY)
if (MACOS AND CLION_IDE AND NOT HasParent)
    # CLion project needs test targets.
    option(PAG_BUILD_TESTS "Build libpag tests" ON)
endif ()

if (PAG_USE_QT)
    set(PAG_USE_SWIFTSHADER OFF)
endif ()

if (PAG_USE_QT OR PAG_USE_SWIFTSHADER)
    set(PAG_USE_OPENGL ON)
else ()
    set(USE_NATIVE_PLATFORM ON)
endif ()

if (PAG_USE_FFAVC)
    set(PAG_USE_LIBAVC OFF)
endif ()

if (PAG_BUILD_TESTS)
    set(PAG_USE_FREETYPE ON)
    set(PAG_USE_HARFBUZZ ON)
    set(PAG_BUILD_SHARED OFF)
endif ()

message("PAG_USE_LIBAVC: ${PAG_USE_LIBAVC}")
message("PAG_USE_RTTR: ${PAG_USE_RTTR}")
message("PAG_USE_HARFBUZZ: ${PAG_USE_HARFBUZZ}")
message("PAG_USE_C: ${PAG_USE_C}")
message("PAG_BUILD_SHARED: ${PAG_BUILD_SHARED}")
message("PAG_BUILD_FRAMEWORK: ${PAG_BUILD_FRAMEWORK}")
message("PAG_BUILD_TESTS: ${PAG_BUILD_TESTS}")

if (NOT CMAKE_OSX_DEPLOYMENT_TARGET)
    if (DEPLOYMENT_TARGET)
        set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET})
    elseif (MACOS)
        if (CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
            set(CMAKE_OSX_DEPLOYMENT_TARGET "11.0")
        else ()
            set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15")
        endif ()
    elseif (IOS)
        set(CMAKE_OSX_DEPLOYMENT_TARGET "9.0")
    endif ()
endif ()

file(STRINGS "src/rendering/PAG.cpp" VERSION_FILE)
set(PAG_VERSION "")
foreach (LINE IN LISTS VERSION_FILE)
    if (LINE MATCHES "\\sdkVersion[^ $]+")
        string(REGEX MATCH "\\\"[^ $]+" VERSION ${LINE})
        string(LENGTH ${VERSION} VERSION_LENGTH)
        MATH(EXPR VERSION_LENGTH "${VERSION_LENGTH}-2")
        string(SUBSTRING ${VERSION} 1 ${VERSION_LENGTH} PAG_VERSION)
        break()
    endif ()
endforeach ()
message("PAG_VERSION: ${PAG_VERSION}")

if (NOT TGFX_DIR)
    set(TGFX_DIR third_party/tgfx)
else ()
    set(HAS_CUSTOM_TGFX_DIR ON)
endif ()
get_filename_component(TGFX_DIR "${TGFX_DIR}" REALPATH BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")

# collects pag include directories.
list(APPEND PAG_INCLUDES src)

# collects pag source files.
file(GLOB_RECURSE SRC_FILES
        src/base/*.*
        src/codec/*.*
        src/rendering/*.*)
list(APPEND PAG_FILES ${SRC_FILES})
file(GLOB COMMON_FILES src/platform/*.*)
list(APPEND PAG_FILES ${COMMON_FILES})

if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
    list(APPEND PAG_COMPILE_OPTIONS -Werror -Wall -Wextra -Weffc++ -pedantic -Werror=return-type)
endif ()

if (MSVC)
    list(APPEND PAG_COMPILE_OPTIONS "/utf-8")
    list(APPEND PAG_COMPILE_OPTIONS /w44251 /w44275)
endif (MSVC)

# Sets flags
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
    list(APPEND PAG_DEFINES DEBUG)
    #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g -O1")
endif ()

if (PAG_BUILD_SHARED)
    list(APPEND PAG_DEFINES PAG_DLL)
endif ()

if (PAG_USE_C)
    file(GLOB PAG_C_FILES src/c/*.* src/c/ext/*.*)
    list(APPEND PAG_FILES ${PAG_C_FILES})
endif ()

if (PAG_USE_LIBAVC)
    list(APPEND PAG_DEFINES PAG_USE_LIBAVC)
    list(APPEND PAG_STATIC_VENDORS libavc)
    list(APPEND PAG_INCLUDES third_party/libavc/common third_party/libavc/decoder)
endif ()

if (PAG_USE_QT)
    # need to set the CMAKE_PREFIX_PATH to local QT installation path, for example :
    # set(CMAKE_PREFIX_PATH /Users/username/Qt5.13.0/5.13.0/clang_64/lib/cmake)
    find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
    find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets OpenGL Quick)
    list(APPEND PAG_SHARED_LIBS Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::OpenGL
            Qt${QT_VERSION_MAJOR}::Quick)
    file(GLOB_RECURSE PLATFORM_FILES src/platform/qt/*.*)
    list(APPEND PAG_FILES ${PLATFORM_FILES})
    list(APPEND PAG_DEFINES GL_SILENCE_DEPRECATION)
    if (MACOS)
        file(GLOB CGL_PLATFORM_FILES src/platform/mac/private/HardwareDecoder.mm)
        list(APPEND PAG_FILES ${CGL_PLATFORM_FILES})
    endif ()
elseif (PAG_USE_SWIFTSHADER)
    file(GLOB SWIFTSHADER_LIBRARIES ${TGFX_DIR}/vendor/swiftshader/${PLATFORM}/${ARCH}/*${CMAKE_SHARED_LIBRARY_SUFFIX})
    list(APPEND PAG_SHARED_LIBS ${SWIFTSHADER_LIBRARIES})
    list(APPEND PAG_INCLUDES ${TGFX_DIR}/vendor/swiftshader/include)
    file(GLOB_RECURSE PLATFORM_FILES src/platform/swiftshader/*.*)
    list(APPEND PAG_FILES ${PLATFORM_FILES})
endif ()

if (PAG_USE_RTTR)
    list(APPEND PAG_DEFINES PAG_USE_RTTR)
    list(APPEND PAG_STATIC_VENDORS rttr)
    list(APPEND PAG_INCLUDES third_party/out/rttr/${INCLUDE_ENTRY})
endif ()

if (PAG_USE_HARFBUZZ)
    list(APPEND PAG_DEFINES PAG_USE_HARFBUZZ)
    list(APPEND PAG_STATIC_VENDORS harfbuzz)
    list(APPEND PAG_INCLUDES third_party/harfbuzz/src)
endif ()

function(find_include_dirs out)
    file(GLOB_RECURSE headers ${ARGN})
    foreach (path ${headers})
        get_filename_component(dir ${path} PATH)
        list(APPEND include_dirs ${dir})
    endforeach ()
    list(REMOVE_DUPLICATES include_dirs)
    set(${out} ${include_dirs} PARENT_SCOPE)
endfunction()

if (WEB)
    list(APPEND PAG_DEFINES PAG_BUILD_FOR_WEB)
    if (USE_NATIVE_PLATFORM)
        file(GLOB_RECURSE PLATFORM_FILES src/platform/web/*.*)
        list(APPEND PAG_FILES ${PLATFORM_FILES})
    endif ()
elseif (IOS)
    # finds all required platform libraries.
    find_library(UIKit_LIBS UIKit REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${UIKit_LIBS})
    find_library(Foundation_LIBS Foundation REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${Foundation_LIBS})
    find_library(QuartzCore_LIBS QuartzCore REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${QuartzCore_LIBS})
    find_library(CoreGraphics_LIBS CoreGraphics REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${CoreGraphics_LIBS})
    find_library(CoreText_LIBS CoreText REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${CoreText_LIBS})
    find_library(VideoToolbox_LIBS VideoToolbox REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${VideoToolbox_LIBS})
    find_library(CoreMedia_LIBS CoreMedia REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${CoreMedia_LIBS})
    find_library(CoreMedia_LIBS CoreMedia REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${CoreMedia_LIBS})
    find_library(ImageIO_LIBS ImageIO REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${ImageIO_LIBS})
    find_library(CORE_VIDEO CoreVideo)
    list(APPEND PAG_SHARED_LIBS ${CORE_VIDEO})
    find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
    list(APPEND PAG_SHARED_LIBS ${ICONV_LIBRARIES})

    if (USE_NATIVE_PLATFORM)
        if (PAG_USE_OPENGL)
            find_library(OpenGLES_LIBS OpenGLES REQUIRED)
            list(APPEND PAG_SHARED_LIBS ${OpenGLES_LIBS})
            list(APPEND PAG_DEFINES GLES_SILENCE_DEPRECATION)
        else ()
            # Uses Metal instead.
            find_library(Metal_LIBS Metal REQUIRED)
            list(APPEND PAG_SHARED_LIBS ${Metal_LIBS})
        endif ()

        file(GLOB_RECURSE PLATFORM_FILES src/platform/ios/*.* src/platform/cocoa/*.*)
        list(APPEND PAG_FILES ${PLATFORM_FILES})
        file(GLOB IOS_PLATFORM_HEADERS src/platform/ios/*.h src/platform/cocoa/*.h)
        list(APPEND PAG_PLATFORM_HEADERS ${IOS_PLATFORM_HEADERS})
        find_include_dirs(IOS_PLATFORM_INCLUDES
                src/platform/ios/*.h
                src/platform/ios/private/*.h
                src/platform/cocoa/*.h
                src/platform/cocoa/private/*.h)
        list(APPEND PAG_INCLUDES ${IOS_PLATFORM_INCLUDES})
    endif ()
elseif (MACOS)
    # finds all required platform libraries.
    find_library(APPLICATION_SERVICES_FRAMEWORK ApplicationServices REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${APPLICATION_SERVICES_FRAMEWORK})
    find_library(QUARTZ_CORE QuartzCore REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${QUARTZ_CORE})
    find_library(COCOA Cocoa REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${COCOA})
    find_library(FOUNDATION Foundation REQUIRED)
    list(APPEND PAG_SHARED_LIBS ${FOUNDATION})
    find_library(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
    list(APPEND PAG_SHARED_LIBS ${ICONV_LIBRARIES})
    find_library(VIDEOTOOLBOX VideoToolbox)
    list(APPEND PAG_SHARED_LIBS ${VIDEOTOOLBOX})
    find_library(CORE_MEDIA CoreMedia)
    list(APPEND PAG_SHARED_LIBS ${CORE_MEDIA})

    if (USE_NATIVE_PLATFORM)
        if (PAG_USE_OPENGL)
            find_library(OpenGL_LIBS OpenGL REQUIRED)
            list(APPEND PAG_SHARED_LIBS ${OpenGL_LIBS})
            list(APPEND PAG_DEFINES GL_SILENCE_DEPRECATION)
        else ()
            # Uses Metal instead.
            find_library(Metal_LIBS Metal REQUIRED)
            list(APPEND PAG_SHARED_LIBS ${Metal_LIBS})
        endif ()

        file(GLOB_RECURSE PLATFORM_FILES src/platform/mac/*.* src/platform/cocoa/*.*)
        list(APPEND PAG_FILES ${PLATFORM_FILES})
        file(GLOB MAC_PLATFORM_HEADERS src/platform/mac/*.h src/platform/cocoa/*.h)
        list(APPEND PAG_PLATFORM_HEADERS ${MAC_PLATFORM_HEADERS})
        find_include_dirs(MAC_PLATFORM_INCLUDES
                src/platform/mac/*.h
                src/platform/mac/private/*.h
                src/platform/cocoa/*.h
                src/platform/cocoa/private/*.h)
        list(APPEND PAG_INCLUDES ${MAC_PLATFORM_INCLUDES})
    endif ()
elseif (ANDROID)
    find_library(LOG_LIB log)
    list(APPEND PAG_SHARED_LIBS ${LOG_LIB})
    find_library(ANDROID_LIB android)
    list(APPEND PAG_SHARED_LIBS ${ANDROID_LIB})
    find_library(JNIGRAPHICS_LIB jnigraphics)
    list(APPEND PAG_SHARED_LIBS ${JNIGRAPHICS_LIB})

    if (PAG_USE_FFAVC)
        list(APPEND PAG_DEFINES PAG_USE_FFAVC)
        file(GLOB FFAVC_LIB android/libpag/libs/${ANDROID_ABI}/libffavc.so)
        list(APPEND PAG_SHARED_LIBS ${FFAVC_LIB})
        list(APPEND PAG_INCLUDES vendor/ffavc/include)
    endif ()

    # optimizes the output size
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/android/libpag/export.def")
    list(APPEND PAG_COMPILE_OPTIONS -ffunction-sections -fdata-sections -Os -fno-exceptions -fno-rtti)

    if (USE_NATIVE_PLATFORM)
        find_library(GLESV2_LIB GLESv2)
        list(APPEND PAG_SHARED_LIBS ${GLESV2_LIB})
        find_library(EGL_LIB EGL)
        list(APPEND PAG_SHARED_LIBS ${EGL_LIB})
        file(GLOB_RECURSE PLATFORM_FILES src/platform/android/*.*)
        list(APPEND PAG_FILES ${PLATFORM_FILES})
    endif ()
elseif (WIN32)
    set(BUILD_USE_64BITS ON)
    list(APPEND PAG_DEFINES NOMINMAX _USE_MATH_DEFINES)

    if (USE_NATIVE_PLATFORM)
        list(APPEND PAG_INCLUDES ${TGFX_DIR}/vendor/angle/include)
        file(GLOB ANGLE_LIBS ${TGFX_DIR}/vendor/angle/${PLATFORM}/${ARCH}/*${CMAKE_STATIC_LIBRARY_SUFFIX})
        list(APPEND PAG_STATIC_LIBS ${ANGLE_LIBS})
        file(GLOB_RECURSE PLATFORM_FILES src/platform/win/*.*)
        list(APPEND PAG_FILES ${PLATFORM_FILES})
    endif ()
    find_library(Bcrypt_LIB Bcrypt)
    list(APPEND PAG_SHARED_LIBS ${Bcrypt_LIB})
    find_library(ws2_32_LIB ws2_32)
    list(APPEND PAG_SHARED_LIBS ${ws2_32_LIB})
elseif (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux")
    # finds all required platform libraries.
    find_package(Threads)
    list(APPEND PAG_SHARED_LIBS ${CMAKE_THREAD_LIBS_INIT})
    list(APPEND PAG_SHARED_LIBS dl)
    list(APPEND PAG_COMPILE_OPTIONS -fPIC -pthread)
    if (USE_NATIVE_PLATFORM)
        find_library(GLESV2_LIB GLESv2)
        list(APPEND PAG_SHARED_LIBS ${GLESV2_LIB})
        find_library(EGL_LIB EGL)
        list(APPEND PAG_SHARED_LIBS ${EGL_LIB})
        file(GLOB_RECURSE PLATFORM_FILES src/platform/linux/*.*)
        list(APPEND PAG_FILES ${PLATFORM_FILES})
    endif ()
endif ()

if (MACOS OR IOS)
    find_library(COMPRESSION_LIBRARIES NAMES compression)
    list(APPEND PAG_SHARED_LIBS ${COMPRESSION_LIBRARIES})
    set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -exported_symbols_list ${CMAKE_CURRENT_SOURCE_DIR}/ios/libpag.lds")
else ()
    list(APPEND PAG_INCLUDES third_party/lz4/lib)
    file(GLOB PLATFORM_FILES third_party/lz4/lib/lz4.c)
    list(APPEND PAG_FILES ${PLATFORM_FILES})
endif ()

if (PAG_USE_C)
    if (ANDROID OR WIN32)
        file(GLOB PLATFORM_FILES src/c/ext/egl/pag_egl_globals.cpp)
        list(APPEND PAG_FILES ${PLATFORM_FILES})
    endif ()
endif ()

list(APPEND PAG_INCLUDES ${TGFX_DIR}/include)
set(TGFX_CACHE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/third_party/tgfx/out/cache)
if (NOT HAS_CUSTOM_TGFX_DIR AND EXISTS ${TGFX_CACHE_DIR})
    message("TGFX_CACHE_DIR: ${TGFX_CACHE_DIR}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_OPENGL=${PAG_USE_OPENGL}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_QT=${PAG_USE_QT}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_SWIFTSHADER=${PAG_USE_SWIFTSHADER}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_FREETYPE=${PAG_USE_FREETYPE}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_PNG_DECODE=${PAG_USE_PNG_DECODE}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_PNG_ENCODE=${PAG_USE_PNG_ENCODE}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_JPEG_DECODE=${PAG_USE_JPEG_DECODE}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_JPEG_ENCODE=${PAG_USE_JPEG_ENCODE}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_WEBP_DECODE=${PAG_USE_WEBP_DECODE}")
    list(APPEND TGFX_OPTIONS "-DTGFX_USE_WEBP_ENCODE=${PAG_USE_WEBP_ENCODE}")
    if (PAG_USE_QT)
        list(APPEND TGFX_OPTIONS "-DCMAKE_PREFIX_PATH=\"${CMAKE_PREFIX_PATH}\"")
    endif ()
    if (CMAKE_BUILD_TYPE MATCHES "Debug")
        list(APPEND TGFX_OPTIONS "-d")
        string(TOLOWER ${CMAKE_BUILD_TYPE} TGFX_BUILD_TYPE)
    endif ()

    set(TGFX_OUTPUT_DIR ${TGFX_CACHE_DIR}/${TGFX_BUILD_TYPE}/${PLATFORM})
    set(TGFX_OUTPUT_LIB ${TGFX_OUTPUT_DIR}/${ARCH}/tgfx${CMAKE_STATIC_LIBRARY_SUFFIX})
    set(TGFX_OUTPUT_MD5 ${TGFX_OUTPUT_DIR}/.tgfx.${ARCH}.md5)
    add_custom_target(tgfx
            COMMAND node build_tgfx ${TGFX_OPTIONS} -p ${PLATFORM} -a ${ARCH} -o ${TGFX_OUTPUT_DIR}
            WORKING_DIRECTORY ${TGFX_DIR}
            BYPRODUCTS ${TGFX_OUTPUT_LIB} ${TGFX_OUTPUT_MD5}
            VERBATIM USES_TERMINAL)
    list(APPEND PAG_STATIC_LIBS ${TGFX_OUTPUT_LIB})
    list(APPEND PAG_DEPEND_TARGETS tgfx)
else ()
    message("TGFX_DIR: ${TGFX_DIR}")
    set(TGFX_USE_OPENGL ${PAG_USE_OPENGL})
    set(TGFX_USE_QT ${PAG_USE_QT})
    set(TGFX_USE_SWIFTSHADER ${PAG_USE_SWIFTSHADER})
    set(TGFX_USE_FREETYPE ${PAG_USE_FREETYPE})
    set(TGFX_USE_PNG_DECODE ${PAG_USE_PNG_DECODE})
    set(TGFX_USE_PNG_ENCODE ${PAG_USE_PNG_ENCODE})
    set(TGFX_USE_JPEG_DECODE ${PAG_USE_JPEG_DECODE})
    set(TGFX_USE_JPEG_ENCODE ${PAG_USE_JPEG_ENCODE})
    set(TGFX_USE_WEBP_DECODE ${PAG_USE_WEBP_DECODE})
    set(TGFX_USE_WEBP_ENCODE ${PAG_USE_WEBP_ENCODE})
    set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
    add_subdirectory(${TGFX_DIR} tgfx EXCLUDE_FROM_ALL)
    list(APPEND PAG_STATIC_LIBS $<TARGET_FILE:tgfx>)
    list(APPEND PAG_DEPEND_TARGETS tgfx)
endif ()

add_vendor_target(pag-vendor STATIC_VENDORS ${PAG_STATIC_VENDORS} SHARED_VENDORS ${PAG_SHARED_VENDORS})
find_vendor_libraries(pag-vendor STATIC PAG_VENDOR_STATIC_LIBRARIES SHARED PAG_VENDOR_SHARED_LIBRARIES)
list(APPEND PAG_STATIC_LIBS ${PAG_VENDOR_STATIC_LIBRARIES})
list(APPEND PAG_SHARED_LIBS ${PAG_VENDOR_SHARED_LIBRARIES})
list(APPEND PAG_DEPEND_TARGETS pag-vendor)

foreach (FILE_PATH ${PAG_FILES})
    get_filename_component(FILE_NAME "${FILE_PATH}" NAME_WE)
    if (NOT FILE_NAME)
        list(APPEND PAG_EXCLUDE_FILES ${FILE_PATH})
    endif ()
endforeach ()

if (PAG_EXCLUDE_FILES)
    list(REMOVE_ITEM PAG_FILES ${PAG_EXCLUDE_FILES})
endif ()

if (WEB)
    add_executable(pag ${PAG_FILES})
    list(APPEND PAG_LINK_OPTIONS --no-entry -lembind -sEXPORT_NAME='Hello2D' -sWASM=1 -sASYNCIFY
            -sUSE_WEBGL2=1 -sEXPORTED_RUNTIME_METHODS=['GL','Asyncify'] -sALLOW_MEMORY_GROWTH=1
            -sMODULARIZE=1 -sENVIRONMENT='web,worker' -sEXPORT_ES6=1 -sUSE_ES6_IMPORT_META=0)
    if (CMAKE_BUILD_TYPE STREQUAL "Debug")
        list(APPEND PAG_COMPILE_OPTIONS -O0 -g3)
        list(APPEND PAG_LINK_OPTIONS -O0 -g3 -sSAFE_HEAP=1 -Wno-limited-postlink-optimizations)
    else ()
        list(APPEND PAG_COMPILE_OPTIONS -Oz)
        list(APPEND PAG_LINK_OPTIONS -Oz)
    endif ()
elseif (PAG_BUILD_SHARED)
    add_library(pag SHARED ${PAG_FILES})
else ()
    add_library(pag STATIC ${PAG_FILES})
    merge_libraries_into(pag ${PAG_STATIC_LIBS})
endif ()
if (PAG_DEPEND_TARGETS)
    add_dependencies(pag ${PAG_DEPEND_TARGETS})
endif ()
target_compile_definitions(pag PUBLIC ${PAG_DEFINES})
target_compile_options(pag PUBLIC ${PAG_COMPILE_OPTIONS})
target_link_options(pag PUBLIC ${PAG_LINK_OPTIONS})
target_include_directories(pag PUBLIC include PRIVATE ${PAG_INCLUDES})
target_link_libraries(pag ${PAG_STATIC_LIBS} ${PAG_SHARED_LIBS})
set_target_properties(pag PROPERTIES PREFIX "")
set_target_properties(pag PROPERTIES OUTPUT_NAME libpag)

if (PAG_BUILD_FRAMEWORK)
    set(PAG_IDENTIFIER "com.tencent.libpag")
    set_target_properties(pag PROPERTIES
            FRAMEWORK TRUE
            PUBLIC_HEADER "${PAG_PLATFORM_HEADERS}"
            MACOSX_FRAMEWORK_IDENTIFIER ${PAG_IDENTIFIER}
            MACOSX_FRAMEWORK_BUNDLE_VERSION ${PAG_VERSION}
            MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PAG_VERSION})
    set(CMAKE_XCODE_ATTRIBUTE_DEFINES_MODULE YES)
    set(CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${PAG_IDENTIFIER})
    if (HasParent)
        set(CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER ${CMAKE_XCODE_ATTRIBUTE_PRODUCT_BUNDLE_IDENTIFIER} PARENT_SCOPE)
    endif ()
endif ()

if (PAG_BUILD_TESTS)
    execute_process(COMMAND git rev-parse --short HEAD OUTPUT_VARIABLE HEAD_COMMIT)
    file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/test/baseline/.cache/HEAD "${HEAD_COMMIT}")
    if (NOT PAG_SKIP_BASELINE_CHECK)
        set(CacheVersionFile ${CMAKE_CURRENT_SOURCE_DIR}/test/baseline/.cache/version.json)
        if (EXISTS ${CacheVersionFile})
            execute_process(COMMAND git diff -G. --name-only origin/main:test/baseline/version.json ${CacheVersionFile} OUTPUT_VARIABLE HAS_DIFF)
        else ()
            set(HAS_DIFF ON)
        endif ()
        if (HAS_DIFF)
            message(WARNING "The local md5 cache is out of date! Please run the 'update_baseline.sh' to regenerate the cache.")
        endif ()
    endif ()

    file(GLOB_RECURSE SRC_FILES test/src/*.*)
    list(APPEND PAG_TEST_FILES ${SRC_FILES})
    list(APPEND PAG_TEST_LIBS pag ${PAG_SHARED_LIBS})
    set(GOOGLE_TEST_DIR ${TGFX_DIR}/third_party/googletest/googletest)
    list(APPEND PAG_TEST_INCLUDES ${PAG_INCLUDES} test/src
            ${GOOGLE_TEST_DIR} ${GOOGLE_TEST_DIR}/include
            ${TGFX_DIR}/third_party/json/include)

    add_vendor_target(test-vendor STATIC_VENDORS googletest CONFIG_DIR ${TGFX_DIR})
    find_vendor_libraries(test-vendor STATIC TEST_VENDOR_STATIC_LIBRARIES)
    list(APPEND PAG_TEST_LIBS ${TEST_VENDOR_STATIC_LIBRARIES})

    file(GLOB FFAVC_LIB vendor/ffavc/${PLATFORM}/${ARCH}/*${CMAKE_SHARED_LIBRARY_SUFFIX})
    list(APPEND PAG_TEST_LIBS ${FFAVC_LIB})
    list(APPEND PAG_TEST_INCLUDES vendor/ffavc/include)

    list(APPEND PAG_TEST_COMPILE_OPTIONS ${PAG_COMPILE_OPTIONS} -fno-access-control)
    list(APPEND PAG_TEST_DEFINES ${PAG_DEFINES})

    foreach (FILE_PATH ${PAG_TEST_FILES})
        get_filename_component(FILE_NAME "${FILE_PATH}" NAME_WE)
        if (NOT FILE_NAME)
            list(APPEND PAG_TEST_EXCLUDE_FILES ${FILE_PATH})
        endif ()
    endforeach ()

    if (PAG_TEST_EXCLUDE_FILES)
        list(REMOVE_ITEM PAG_TEST_FILES ${PAG_TEST_EXCLUDE_FILES})
    endif ()

    # used to update the local md5 data for baseline testing.
    add_executable(UpdateBaseline ${PAG_TEST_FILES})
    add_dependencies(UpdateBaseline test-vendor)
    target_include_directories(UpdateBaseline PUBLIC ${PAG_TEST_INCLUDES})
    target_compile_definitions(UpdateBaseline PUBLIC ${PAG_TEST_DEFINES} UPDATE_BASELINE)
    target_compile_options(UpdateBaseline PUBLIC ${PAG_TEST_COMPILE_OPTIONS})
    target_link_options(UpdateBaseline PRIVATE ${PAG_TEST_LINK_OPTIONS})
    target_link_libraries(UpdateBaseline ${PAG_TEST_LIBS})

    # used to generate baseline images to the out/ directory. each image has a "_base" suffix.
    add_executable(GenerateImages ${PAG_TEST_FILES})
    add_dependencies(GenerateImages test-vendor)
    target_include_directories(GenerateImages PUBLIC ${PAG_TEST_INCLUDES})
    target_compile_definitions(GenerateImages PUBLIC ${PAG_TEST_DEFINES} GENERATOR_BASELINE_IMAGES)
    target_compile_options(GenerateImages PUBLIC ${PAG_TEST_COMPILE_OPTIONS})
    target_link_options(GenerateImages PRIVATE ${PAG_TEST_LINK_OPTIONS})
    target_link_libraries(GenerateImages ${PAG_TEST_LIBS})

    add_executable(PAGUnitTest ${PAG_TEST_FILES})
    add_dependencies(PAGUnitTest test-vendor)
    target_include_directories(PAGUnitTest PUBLIC ${PAG_TEST_INCLUDES})
    target_compile_definitions(PAGUnitTest PUBLIC ${PAG_TEST_DEFINES} SKIP_FRAME_COMPARE)
    target_compile_options(PAGUnitTest PUBLIC ${PAG_TEST_COMPILE_OPTIONS})
    target_link_options(PAGUnitTest PRIVATE ${PAG_TEST_LINK_OPTIONS})
    target_link_libraries(PAGUnitTest ${PAG_TEST_LIBS})

    add_executable(PAGFullTest ${PAG_TEST_FILES})
    add_dependencies(PAGFullTest test-vendor)
    target_include_directories(PAGFullTest PUBLIC ${PAG_TEST_INCLUDES})
    target_compile_definitions(PAGFullTest PUBLIC ${PAG_TEST_DEFINES})
    target_compile_options(PAGFullTest PUBLIC ${PAG_TEST_COMPILE_OPTIONS})
    target_link_options(PAGFullTest PRIVATE ${PAG_TEST_LINK_OPTIONS})
    target_link_libraries(PAGFullTest ${PAG_TEST_LIBS})
endif ()
